// Simple JavaScript Inheritance
// By John Resig http://ejohn.org/
// MIT Licensed. 
// Inspired by base2 and Prototype
/**
 * Base class
 * @class Class
 */
(function(){
  var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;
  // The base Class implementation (does nothing)
  this.Class = function(){};
  
  // Create a new Class that inherits from this class
  Class.extend = function(prop) {
    var _super = this.prototype;
    
    // Instantiate a base class (but only create the instance,
    // don't run the init constructor)
    initializing = true;
    var prototype = new this();
    initializing = false;
    
    // Copy the properties over onto the new prototype
    for (var name in prop) {
      // Check if we're overwriting an existing function
      prototype[name] = typeof prop[name] == "function" && 
        typeof _super[name] == "function" && fnTest.test(prop[name]) ?
        (function(name, fn){
          return function() {
            var tmp = this._super;
            
            // Add a new ._super() method that is the same method
            // but on the super-class
            this._super = _super[name];
            
            // The method only need to be bound temporarily, so we
            // remove it when we're done executing
            var ret = fn.apply(this, arguments);        
            this._super = tmp;
            
            return ret;
          };
        })(name, prop[name]) :
        prop[name];
    }
    
    // The dummy class constructor
    function Class() {
      // All construction is actually done in the init method
      if ( !initializing && this.init )
        this.init.apply(this, arguments);
    }
    
    // Populate our constructed prototype object
    Class.prototype = prototype;
    
    // Enforce the constructor to be what we expect
    Class.prototype.constructor = Class;

    // And make this class extendable
    Class.extend = arguments.callee;
    
    return Class;
  };
})();//Utility functions
function merge(s, a) {
    if (a && s) for (var c in a){s[c]=a[c];}return s;
}

function isFunction(obj) {
  return !!(obj && obj.constructor && obj.call && obj.apply);
}

function isArray(obj) {
    return obj instanceof Array;
}/**
 * The Starting point for this library, call EasySvg.svg method to create a SVG canvas element
 * @module EasySvg
 * @class EasySvg
 * @static
 * @namespace 
 * @author Helge Andersen
 * @version 0.0.1.0
 */
var EasySvg = {    
    /**
     * Creates an svg DOM element
     * @method svg
     * @param {object} config 
     * @return {SvgCanvas}
     */
    svg: function(config) {
        if (!EasySvg.isSupported()) {
            console.log("SVG is not supported in this browser version!");
            return undefined;
        }
        var _c = merge({el:document.body, attr:{}, shapes:[], defs:[]}, config);        
        return new SvgCanvas(_c).attr(_c.attr);        
    },
    
    /**
     * Check if SVG is supported by the browser
     * @method isSupported
     * @return {Boolean}
     */
    isSupported: function() {
        return window.SVGAngle || document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#Shape", "1.0");

    }
}/**
 * Class for a single Svg element
 * @class SvgElement
 * @extends Class
 * @constructor
 * @param {string} type Type of svg element. Eg: 'circle', 'rect', 'g', etc.
 * @param {SVGElement} Dom svg DOM element of the parent container
 * @param {SvgCanvas} The svg stage/canvas
 * @author Helge Andersen
 */
var SvgElement = {
    canvas: null,

    dom: null,
    
    _listeners: [],
    
    /**
     * Constructor
     * @private
     */
    init: function(type, parent, canvas) {
        var svg = document.createElementNS("http://www.w3.org/2000/svg", type);
        this.dom = svg;
        this.canvas = canvas ? canvas : svg;
        (parent ? parent : document.body).appendChild(svg);
    },
    
    /**
     *  Set attributes for an element if argument is supplied. <br>
     *  If no argument is supplied return the attributes as a javascript object.<br>
     *  Read SVG specifications for valid attributes<br>
     *  Example: el.attr({ fill: "#ff00ff" });
     *  @method attr
     *  @param {object} v 
     *  @return {SvgElement} this  
     */
    attr: function(v) {
        if (!v) {
            var a = {}, d = this.dom.attributes;
            for (var i=0; i<d.length; i++) a[d[i].name] = d[i].value;return a;
        }
        for (var a in v){this.dom.setAttribute(a, v[a]);} 
        return this;
    },
    
    /**
     * Register an event handler
     * @method on
     * @param {String} e name of the event
     * @param {Function} fn
     * @param {Object} scope set the scope you want the function to run in
     * @return {SvgElement} this
     */
    on: function(e, fn, scope)  {
        var evFn = scope ? function() {return fn.call(scope);} : fn;
        this.dom.addEventListener(e, evFn, false);   
        return this;
    },
    
    /**
     *  Add animation for an element. <br>
     *  Read SVG specifications for valid attributes<br>
     *  Example: el.animate({ attributeName: "x", values: "0;40", dur: "3s", repeatCount: "indefinite" });
     *  @method attr
     *  @param {object} attr 
     *  @return {SvgElement} this  
     */
    animate: function(attr) {
        return new SvgElement("animate", this.dom, this.canvas).attr(attr);
    },
    
    /**
     *  Add animation transformation for an element. <br>
     *  Read SVG specifications for valid attributes<br>
     *  Example: el.animateTransform({ attributeName:"transform", type:"rotate", from:"0", to:"90", dur:"10s", repeatCount:"indefinite" });
     *  @method attr
     *  @param {object} attr 
     *  @return {SvgElement} this  
     */
    animateTransform: function(attr) {
        return new SvgElement("animateTransform", this.dom, this.canvas).attr(attr);
    },
    
    /**
     *  Add animation motion for an element. <br>
     *  Read SVG specifications for valid attributes<br>
     *  Example: el.animateMotion({ path:"M10 50 C10 0 90 0 90 50", dur:"10s", rotate:"auto", repeatCount:"indefinite" });
     *  @method attr
     *  @param {object} attr 
     *  @return {SvgElement} this  
     */
    animateMotion: function(attr) {
        return new SvgElement("animateMotion", this.dom, this.canvas).attr(attr);
    }
};
SvgElement = Class.extend(SvgElement);
/**
 * @class SvgContainer
 * @extends SvgElement
 */
var SvgContainer = {
    /**
     * @private
     * @method shape
     * @param {String} t Svg element type 
     * @param {Object} a Svg element attributes
     * @return {SvgElement}
     */
    shape: function(t, a) {        
        return new SvgElement(t, this.dom, this.canvas).attr(a);
    },
    /**
     * @method rect
     * @param {Object} a Svg element attributes
     * @return {SvgElement}
     */
    rect: function(a) {
        return this.shape("rect", a);
    },
    /**
     * @method circle
     * @param {Object} a Svg element attributes
     * @return {SvgElement}
     */
    circle: function(a) {
        return this.shape("circle", a);
    },
    /**
     * @method ellipse
     * @param {Object} a Svg element attributes
     * @return {SvgElement}
     */
    ellipse: function(a) {
        return this.shape("ellipse", a);
    },
    /**
     * @method line
     * @param {Object} a Svg element attributes
     * @return {SvgElement}
     */
    line: function(a) {
        return this.shape("line", a);
    },
    /**
     * @method polyline
     * @param {Object} a Svg element attributes
     * @return {SvgElement}
     */
    polyline: function(a) {
        return this.shape("polyline", a);
    },
    /**
     * @method polygon
     * @param {Object} a Svg element attributes
     * @return {SvgElement}
     */
    polygon: function(a) {
        return this.shape("polygon", a);
    },
    /**
     * @method text
     * @param {String} text The value of the text element
     * @param {Object} a Svg element attributes
     * @return {SvgText}
     */
    text: function(text, a) {
        return new SvgText(text, this.dom, this.canvas).attr(a);
    },
    /**
     * @method image
     * @param {String} href The uri of the image
     * @param {Object} a Svg element attributes
     * @return {SvgImage}
     */
    image: function(href, a) {
        return new SvgImage(href, this.dom, this.canvas).attr(a);
    },
    /**
     * @method group
     * @param {Object} a Svg element attributes
     * @return {SvgContainer}
     */
    group: function(a) {
        return new SvgContainer("g", this.dom, this.canvas).attr(a ? a : {});
    },  
    /**
     * @method use
     * @param {String} id Id of the symbol element that you want to use
     * @param {Object} a Svg element attributes
     * @return {SvgUse}
     */
    use: function(id,a) {
        return new SvgUse("#"+id, this.dom, this.canvas).attr(a ? a : {});
    },
    
    /**
     * @method add
     * @param {SVGElement || SVGElement[] || Config object/array} svgEl
     * @return {SvgContainer}
     */
    add: function(svgEl) {  
        var dom = this.dom;
        var canvas = this.canvas;
        var addChild = function(o) {
            if (o instanceof SvgElement) {
                dom.appendChild(o.dom);
            } else {
                new SvgConfigParser(o,dom, canvas);
            }
        };
        
        if (isArray(svgEl)) {
            for (var i=0; i<svgEl.length; i++) {
                addChild(svgEl[i]);
            }
        } else {
            addChild(svgEl);
        }
        return this;
    },
    
    /**
     * @method clear
     */
    clear: function() {
        while (this.dom.firstChild) {
            this.dom.removeChild(this.dom.firstChild);
        }
    }
};
SvgContainer = SvgElement.extend(SvgContainer);/**
 * Creates a SVG canvas element to host the shapes
 * @class SvgCanvas
 * @extends SvgContainer
 * @constructor
 * @param {object} config  See configuration attributes
 * @author Helge Andersen
 */
/**
 * A dom element to host the svg canvas, can be a div, document.body etc.
 * @config el 
 * @type DOMElement
 */
/**
 * A config object with the attributes the svg element
 * @config attr 
 * @type Object
 */
var SvgCanvas = {
    /**
     * Constructor
     * @method init
     * @private
     */
    init: function(config) {        
        this._super("svg", config.el);
        this.canvas = this.dom;
        this.attr({
            'version':'1.1', 
            width:'10cm', 
            height:'10cm'
        });
        if (config.attr) this.attr(config.attr);
    },
    
    /**
     * Creates a defines section in the SVG element
     * @method defines
     * @param {object} a Config object with attributes, read SVG specifications for valid attributes
     * @return {SvgDefines}
     */
    defines: function(a) {
        return new SvgDefines(this.dom, this.dom).attr(a ? a : {});
    }
};
SvgCanvas = SvgContainer.extend(SvgCanvas);/**
 * Class for parsing json and generate SvgContainer and SvgElement objects
 * @class SvgConfigParser
 * @extends Class
 * @constructor
 * @param {object} config  See configuration attributes
 * @param {SVGElement} Dom svg element of the parent container
 * @param {SvgCanvas} The svg stage/canvas
 */
/**
 * The svg element type
 * @config type 
 * @type String
 */
/**
 * An array of config objects which represents the child elements
 * @config items 
 * @type Array
 */
/**
 * An config object with attributes of the svg element
 * @config attr 
 * @type Object
 */
/**
 * An config object with event listeners for the svg element
 * @config listeners 
 * @type Object
 */
/**
 * An config object which represents a child animation element
 * @config animate 
 * @type Object
 */
/**
 * An config object which represents a child animationTransform element
 * @config animateTransform 
 * @type Object
 */
/**
 * An config object which represents a child animationMotion element
 * @config animateMotion 
 * @type Object
 */
var SvgConfigParser = {
    svg: null,
    
    /**
     * @private
     * @method init
     * @memberOf SvgConfigParser
     */
    init: function(config, container, canvas) {
        var svg = canvas, 
            parse = function(o, c) {
                if (o && typeof(o)=="object" && o.type) {
                    var isContainer = (o.items && isArray(o.items));
                    var el = isContainer ? new SvgContainer(o.type, c, svg) : new SvgElement(o.type, c, svg);
                    if (o.attr) el.attr(o.attr);
                    if (isContainer) {
                        for (var i=0; i<o.items.length; i++) parse(o.items[i], el.dom);
                    }
                    if (o.listeners) {
                        for (var l in o.listeners) {
                            el.on(l, o.listeners[l], el);
                        }
                    }
                    if (o.animate) {
                        if (isArray(o.animate)) {
                            for (var i=0; i<o.animate.length; i++) el.animate(o.animate[i].attr ? o.animate[i].attr : {});
                        } else
                            el.animate(o.animate.attr ? o.animate.attr : {});
                        
                    }
                    if (o.animateTransform) {
                        if (isArray(o.animateTransform)) {
                            for (var i=0; i<o.animateTransform.length; i++) el.animateTransform(o.animateTransform[i].attr ? o.animateTransform[i].attr : {});
                        } else
                            el.animateTransform(o.animateTransform.attr ? o.animateTransform.attr : {});
                        
                    }
                    if (o.animateMotion) {
                        if (isArray(o.animateMotion)) {
                            for (var i=0; i<o.animateMotion.length; i++) el.animateMotion(o.animateMotion[i].attr ? o.animateMotion[i].attr : {});
                        } else
                            el.animateMotion(o.animateMotion.attr ? o.animateMotion.attr : {});
                        
                    }
                }
            };
        
        this.svg=canvas;
        parse(config, container);
    }   
    
};
SvgConfigParser = Class.extend(SvgConfigParser);/**
 * The SVG defines section
 * @class SvgDefines
 * @extends SvgContainer
 */
var SvgDefines = {
    /**
     * Constructor
     * @private
     */
    init: function(parent, canvas) {        
        this._super("defs", parent, canvas);
    },
    /**
     * Creates a symbol element in the SVG defines section
     * @method symbol
     * @param {object} a Config object with attributes, read SVG specifications for valid attributes
     * @return {SvgContainer}
     */
    symbol: function(a) {
        return new SvgContainer("symbol", this.dom, this.canvas).attr(a ? a : {});
    },
    /**
     * Creates a lineargradient element in the SVG defines section
     * @method linearGradient
     * @param {object} a Config object with attributes, read SVG specifications for valid attributes
     * @return {SvgLinearGradient}
     */
    linearGradient: function(a) {
        return new SvgLinearGradient(this.dom, this.canvas).attr(a ? a : {});
    },
    /**
     * Creates a radialgradient element in the SVG defines section
     * @method radialGradient
     * @param {object} a Config object with attributes, read SVG specifications for valid attributes
     * @return {SvgRadialGradient}
     */
    radialGradient: function(a) {
        return new SvgRadialGradient(this.dom, this.canvas).attr(a ? a : {});
    }
    
};
SvgDefines = SvgContainer.extend(SvgDefines);/**
 * Class for parsing json and generate SvgContainer and SvgElement objects
 * @class SvgDefsParser
 * @extends Class
 * @constructor
 * @param {object} config  See configuration attributes
 * @param {SvgCanvas} The svg stage/canvas
 */
/**
 * An array of config objects which represents the child elements
 * @config items 
 * @type Array
 */
var SvgDefsParser = {
    svg: null,
    
    /**
     * @private
     * @method init
     * @memberOf SvgConfigParser
     */
    init: function(config, canvas) {
        var svg = canvas, 
            parse = function(o) {
                if (o && typeof(o)=="object") {
                    var el = new SvgDefines(svg,svg);
                    var elParser = new SvgConfigParser(o, svg, svg);
                    for (var i=0; i<o.items.length; i++) {
                        if (o.items[i].type=="symbol") {
                            
                        } else 
                            elParser.parse(o.items[i], el.dom);                    
                    }
                }
            };
        
        this.svg=canvas;
        parse(config);
    }   
    
};
SvgDefsParser = Class.extend(SvgDefsParser);/**
 * Base class for gradient
 * @class SvgGradient
 * @extends SvgElement
 */
var SvgGradient = {      
    /**
     * Add a new gradient stop value
     * @method stop 
     * @param {Number} o offset
     * @param {String} c Color
     * @return {SvgGradient}
     */
    stop: function(o, c) {
        new SvgElement("stop", this.dom, this.canvas).attr({
             'offset':o,
             'stop-color':c
        });
        return this; 
    }
};
SvgGradient = SvgElement.extend(SvgGradient);/**
 * Creates a SVG image element
 * @class SvgImage
 * @extend SvgElement
 */
var SvgImage = {
    /**
     * @private
     */
    _title: null,
    
    /**
     * @private
     */
    init: function(href, parent, canvas) {
        this._super("image", parent, canvas);
        this.dom.setAttributeNS("http://www.w3.org/1999/xlink", 'href', href);
        this._title = new SvgElement("title", this.dom, this.canvas);
        this._title.dom.appendChild(document.createTextNode(""));
    },
    /**
     * @method title
     * @param {String} t Image title text
     * 
     */
    title: function(t) {
        this._title.dom.childNodes[0].nodeValue = t;        
    }
};
SvgImage = SvgElement.extend(SvgImage);/**
 * Linear gradient element
 * @class SvgLinearGradient
 * @extends SvgGradient
 * @constructor
 * @param {SVGElement} Dom svg element of the parent container
 * @param {SvgCanvas} The svg stage/canvas
 */
var SvgLinearGradient = {        
    /**
     * Constructor
     * @private
     */
    init: function(parent, canvas) {        
        this._super("linearGradient", parent, canvas);
    }
};
SvgLinearGradient = SvgGradient.extend(SvgLinearGradient);/**
 * Radial gradient element
 * @class SvgRadialGradient
 * @extends SvgGradient
 * @constructor
 * @param {SVGElement} Dom svg element of the parent container
 * @param {SvgCanvas} The svg stage/canvas
 */
var SvgRadialGradient = {        
    /**
     * Constructor
     * @private
     */
    init: function(parent, canvas) {        
        this._super("radialGradient", parent, canvas);
    }
};
SvgRadialGradient = SvgGradient.extend(SvgRadialGradient);/**
 * SVG text element
 * @class SvgText
 * @extends SvgElement
 * @constructor
 * @param {String} t Text value to render.
 * @param {SVGElement} Dom svg DOM element of the parent container
 * @param {SvgCanvas} The svg stage/canvas
 */
var SvgText = {
    /**
     * Constructor
     * @private
     */
    init: function(t, parent, canvas) {        
        this._super("text", parent, canvas);
        this.dom.appendChild(document.createTextNode(t));
    },
    /**
     * Add a new tspan element inside this text element
     * @method tspan 
     * @param {Object} a attributes
     * @param {String} t The text to render
     * @return {SvgElement} a tspan element
     */
    tspan: function(a, t) {
        var tspan = new SvgElement("tspan", this.dom, this.canvas).attr(a);
        tspan.dom.appendChild(document.createTextNode(t));
        return tspan; 
    }
};
SvgText = SvgElement.extend(SvgText);/**
 * A SVG use element
 * @class SvgUse
 * @extends SvgElement
 * @constructor
 * @param {String} href The IRI/URI to the symbol to render.
 * @param {SVGElement} Dom svg DOM element of the parent container
 * @param {SvgCanvas} The svg stage/canvas
 */
var SvgUse = {
    /**
     * Constructor
     * @private
     */
    init: function(href, parent, canvas) {
        this._super("use", parent, canvas);
        this.dom.setAttributeNS("http://www.w3.org/1999/xlink", 'href', href);
    }
};
SvgUse = SvgElement.extend(SvgUse);